using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework;
using System.Threading;
using Xyne.Events;
using Xyne.Utilities;
using Xyne.Actions;
using Xyne.Templates.BattleEffects;

namespace Xyne.Network
{
    public abstract class NetworkComponent : GameComponent
    {
        protected NetworkSessionType ConnectionType = NetworkSessionType.SystemLink;
        private List<StateEntity> entities;
        private NetworkSession session;
        private LocalNetworkGamer localGamer;
        private GameObjects wizard; 
        private Queue<NetworkData> data;
        private PacketWriter writer;

        protected List<StateEntity> StateEntities
        {
            get { return entities; }
        }

        public NetworkSession Session
        {
            get { return session; }
            set { session = value; }
        }

        public LocalNetworkGamer Gamer
        {
            get { return localGamer; }
            set { localGamer = value; }
        }

        public GameObjects Wizard
        {
            get { return wizard; }
            set { wizard = value; }
        }

        public Queue<NetworkData> DataQueue
        {
            get { return data; }
        }

        public NetworkComponent(Game game) : base(game)
        {
            entities = new List<StateEntity>();
            writer = new PacketWriter();
            data = new Queue<NetworkData>();
            SignedInGamer.SignedOut += new EventHandler<SignedOutEventArgs>(HandleSignedOut);
        }

        /// <summary>
        /// The bottleneck where all network-based events go (i.e. game ending)
        /// </summary>
        /// <param name="e">The event</param>
        public abstract void HandleEvent(Event e);

        /// <summary>
        /// The bottleneck where all network-based actions go (i.e. game fireball)
        /// </summary>
        /// <param name="e">The action</param>
        public abstract void HandleAction(Action a);

        public void AddStateEntity(StateEntity entity)
        {
            if (!entities.Contains(entity))
                entities.Add(entity);
        }

        public void RemoveStateEntity(StateEntity entity)
        {
            entities.Remove(entity);
        }

        private void HandleSignedOut(object sender, SignedOutEventArgs e)
        {
            // If the playing user is no longer signed in, end game...
        }

        public void SetReady()
        {
            if (session != null)
            {
                foreach (LocalNetworkGamer gamer in session.LocalGamers)
                {
                    gamer.IsReady = true;
                }
            }
        }

        public void CloseSession()
        {
            if (session != null && !session.IsDisposed)
            {
                if (session.IsHost && session.SessionState == NetworkSessionState.Playing)
                {
                    session.EndGame();
                }
            }
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            SendData();

            if (Session != null && !Session.IsDisposed)
            {
                Session.Update();
            }
        }

        public void SendData()
        {
            if (Gamer != null && data.Count > 0)
            {
                while (data.Count > 0)
                {
                    NetworkData packet = data.Dequeue();
                    writer.Write((ulong)packet.DataType);
                    writer.Write(Gamer.Gamertag);
                    packet.Serialize(writer);
                }
                Gamer.SendData(writer, Session.IsHost ? SendDataOptions.InOrder : SendDataOptions.Reliable);
            }
        }
    }
}
